<!DOCTYPE html>
<html>
<head>
    <title>Electromagnetic Field Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            border: 1px solid #ccc;
            background-color: #fff;
        }
    </style>
</head>
<body>
    <canvas id="physicsCanvas" width="500" height="450"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        // Helper function to draw an arrow on a line segment
        function drawArrowOnLine(p1, p2, position = 0.5, size = 8) {
            const dx = p2.x - p1.x;
            const dy = p2.y - p1.y;
            const angle = Math.atan2(dy, dx);
            const midX = p1.x + dx * position;
            const midY = p1.y + dy * position;

            ctx.save();
            ctx.translate(midX, midY);
            ctx.rotate(angle);
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(-size, -size / 2);
            ctx.moveTo(0, 0);
            ctx.lineTo(-size, size / 2);
            ctx.stroke();
            ctx.restore();
        }

        // --- Main Drawing ---
        ctx.translate(canvas.width / 2, 100);

        // Parameters
        const L = 120; // Side length of the square
        const theta_deg = 15;
        const theta_rad = theta_deg * Math.PI / 180;
        const axisWidth = 200;
        const axisExt = 60; // How much the axis line extends

        // Define points for the axis of rotation
        const O = { x: -axisWidth / 2, y: 10 };
        const O_prime = { x: axisWidth / 2, y: -10 };
        
        // --- Styles ---
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'white';
        ctx.lineWidth = 1.5;

        // --- Draw the Axis of Rotation (O-O') ---
        const axis_angle = Math.atan2(O_prime.y - O.y, O_prime.x - O.x);
        const start_axis = {
            x: O.x - axisExt * Math.cos(axis_angle),
            y: O.y - axisExt * Math.sin(axis_angle)
        };
        const end_axis = {
            x: O_prime.x + axisExt * Math.cos(axis_angle),
            y: O_prime.y + axisExt * Math.sin(axis_angle)
        };
        ctx.beginPath();
        ctx.moveTo(start_axis.x, start_axis.y);
        ctx.lineTo(end_axis.x, end_axis.y);
        ctx.stroke();

        // --- Draw Points O and O' ---
        ctx.beginPath();
        ctx.arc(O.x, O.y, 4, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();

        ctx.beginPath();
        ctx.arc(O_prime.x, O_prime.y, 4, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();

        // --- Draw Initial Position (Dashed Lines) ---
        ctx.save();
        ctx.setLineDash([6, 4]);
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 1;

        const P_initial = { x: O.x, y: O.y + L };
        const Q_initial = { x: O_prime.x, y: O_prime.y + L };

        // Vertical lines
        ctx.beginPath();
        ctx.moveTo(O.x, O.y);
        ctx.lineTo(P_initial.x, P_initial.y);
        ctx.moveTo(O_prime.x, O_prime.y);
        ctx.lineTo(Q_initial.x, Q_initial.y);
        // Bottom line
        const bottom_dash_start = { x: O.x, y: O.y + L };
        const bottom_dash_end = { x: O_prime.x, y: O_prime.y + L};
        ctx.moveTo(O.x, O.y+L);
        // In the original image the bottom dashed line is parallel to OO'
        const initial_bottom_p1 = { x: O.x, y: O.y + L };
        const initial_bottom_p2 = { x: O_prime.x, y: O.y + L }; //This is not parallel to OO', let's fix it
        const initial_bottom_p2_corrected = { x: O_prime.x, y: O_prime.y + L};
        // The diagram has the bottom dashed line connecting the vertical drops.
        ctx.moveTo(O.x, O.y + L);
        ctx.lineTo(O_prime.x, O_prime.y + L);
        ctx.stroke();
        ctx.restore();


        // --- Draw Final Position (Solid Lines) ---
        const P = { x: O.x + L * Math.sin(theta_rad), y: O.y + L * Math.cos(theta_rad) };
        const Q = { x: O_prime.x + L * Math.sin(theta_rad), y: O_prime.y + L * Math.cos(theta_rad) };
        
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(O.x, O.y);
        ctx.lineTo(P.x, P.y);
        ctx.lineTo(Q.x, Q.y);
        ctx.lineTo(O_prime.x, O_prime.y);
        ctx.stroke();

        // --- Draw Current Arrows ---
        ctx.fillStyle = 'black';
        ctx.lineWidth = 1.5;
        // In-flow arrow on the axis
        drawArrowOnLine(start_axis, O, 0.7, 10);
        // Arrow on the left side
        drawArrowOnLine(O, P, 0.5, 10);
        // Arrow on the bottom side
        drawArrowOnLine(P, Q, 0.5, 10);
        // Arrow on the right side
        drawArrowOnLine(Q, O_prime, 0.5, 10);
        // Out-flow arrow on the axis
        drawArrowOnLine(O_prime, end_axis, 0.3, 10);

        // --- Draw Angle Arc and Label ---
        ctx.lineWidth = 1;
        ctx.beginPath();
        const arc_radius = 25;
        ctx.arc(O.x, O.y, arc_radius, Math.PI / 2, Math.PI / 2 + theta_rad);
        ctx.stroke();
        
        ctx.font = 'italic 18px Times New Roman';
        ctx.fillText('θ', O.x + 15, O.y + 22);

        // --- Draw Labels ---
        ctx.font = "italic 20px 'Times New Roman'";
        ctx.fillText('O', O.x - 25, O.y + 5);
        ctx.fillText("O'", O_prime.x + 10, O_prime.y - 5);
        ctx.fillText('I', (P.x + Q.x) / 2, P.y + 20);

        // --- Draw Caption ---
        ctx.font = '20px "SimSun"';
        ctx.fillStyle = 'black';
        ctx.fillText('习题 8-40 图', -55, 250);

    </script>
</body>
</html>